﻿namespace SoftSource.Timecard.Entry
{
    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Ria.ApplicationServices;
    using SoftSource.Common;
    using SoftSource.Controls;
    using SoftSource.Timecard.Entry.Controller;
    using SoftSource.Timecard.Entry.Helpers;
    using SoftSource.Timecard.Entry.Model;
    using SoftSource.Timecard.Entry.Resources;

    public partial class App : Application
    {
        #region Fields
        private BusyIndicator progressIndicator;
        #endregion Fields

        public App()
        {
            InitializeComponent();
        }

        #region Public

        #region Properties
        public static IController Controller { get; private set; }
        public static IModel Model { get; private set; }
        new public static App Current
        {
            get { return (App)Application.Current; }
        }
        #endregion Properties

        #region Methods
        public void LoadUser()
        {
            WebContext.Current
                .LoadUser()
                .Do(operation => this.InitializeUserLoaded())
                .Subscribe();
        }

        public void Logout()
        {
            WebContext.Current
                .Logout()
                .Do(operation => this.LoadUser())
                .Subscribe();
            this.ResetUI();
        }
        #endregion Methods

        #endregion Public

        #region Private

        #region Properties

        private Root RootUI
        {
            get { return this.progressIndicator.Content as Root; }
        }

        #endregion Properties

        #region Methods
        /// <summary>
        ///     Initializes the <see cref="Application.RootVisual"/> property. The
        ///     initial UI will be displayed before the LoadUser operation has completed
        ///     (The LoadUser operation will cause user to be logged automatically if
        ///     using windows authentication or if the user had selected the "keep
        ///     me signed in" option on a previous login).
        /// </summary>
        protected virtual void InitializeRootVisual()
        {
            this.progressIndicator = new BusyIndicator();
            this.progressIndicator.Content = new Root();
            this.progressIndicator.HorizontalContentAlignment = HorizontalAlignment.Stretch;
            this.progressIndicator.VerticalContentAlignment = VerticalAlignment.Stretch;

            // Let the user know we're trying to authenticate him
            this.progressIndicator.BusyContent = ApplicationStrings.ActivityLoadingUser;

            this.RootVisual = this.progressIndicator;
        }

        private void AppLoading()
        {
            this.progressIndicator.IsBusy = true;
        }

        private void AppLoaded()
        {
            this.RootUI.Content = App.Controller.CreateMainView();
            this.progressIndicator.IsBusy = false;
        }

        private void ResetUI()
        {
            this.RootUI.Content = null;
        }

        /// <summary>
        ///     Invoked when the <see cref="LoadUserOperation"/> completes. Use this
        ///     event handler to switch from the "loading UI" you created in
        ///     <see cref="InitializeRootVisual"/> to the "application UI"
        /// </summary>
        private void InitializeUserLoaded()
        {
            Action completed = () =>
                {
                    App.Model = new DefaultModel(this.RootUI.Dispatcher);
                    App.Controller = new DefaultController();

                    this.AppLoading();
                    App.Model.LoadData()
                        .ObserveOnDispatcher()
                        .Subscribe(unit => this.AppLoaded());
                };

            if (WebContext.Current.User.IsAuthenticated)
            {
                completed();
            }
            else
            {
                this.ShowLoginWindow(completed);
            }
        }

        private void ShowLoginWindow(Action completed)
        {
            ChildWindow cw = new ChildWindow();
            cw.Title = "Login";
            cw.HasCloseButton = false;

            Action done = () =>
                {
                    cw.Close();
                    if (WebContext.Current.User.IsAuthenticated)
                        completed();
                };

            cw.Content = SharedController.CreateLoginView(
                WebContext.Current.Authentication,
                App.FormatUsername,
                done);
            cw.Show();
        }

        private static string FormatUsername(string username)
        {
            string text = username;
            string formattedUsername;

            // shaun@sftsrc.com
            // sftsrc\shaun
            // shaun
            if (text.Contains('@'))
            {
                formattedUsername = string.Format("SFTSRC\\{0}", text.Split('@').First());
            }
            else
            {
                formattedUsername = text.Contains('\\') ? text : string.Format("SFTSRC\\{0}", text);
            }

            return formattedUsername;
        }
        #endregion Methods

        #region Events
        private void Application_Startup(object sender, StartupEventArgs e)
        {
            // This will enable you to bind controls in XAML files to WebContext.Current
            // properties
            this.Resources.Add("WebContext", WebContext.Current);

            this.InitializeRootVisual();

            if (!Current.IsRunningOutOfBrowser)
            {
                MouseWheel.Enable(this.RootVisual);
            }

            this.LoadUser();
        }

        private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            // HACK: The RIA Web context will not update when the ASP.NET session has expired. "Access denied" is part of the error message, so we force login again.
            if (e.ExceptionObject.GetFullException().Contains("Access denied"))
            {
                this.Logout();
                e.Handled = true;
                return;
            }

            // If the app is running outside of the debugger then report the exception using
            // a ChildWindow control.
            if (!System.Diagnostics.Debugger.IsAttached)
            {
                // NOTE: This will allow the application to continue running after an exception has been thrown
                // but not handled. 
                // For production applications this error handling should be replaced with something that will 
                // report the error to the website and stop the application.
                e.Handled = true;
                ErrorWindow.CreateNew(e.ExceptionObject);
            }
        }

        /// <summary>
        /// Toggle the drop down for the control, part of the custom template.
        /// </summary>
        /// <param name="sender">The source object.</param>
        /// <param name="e">The event arguments.</param>
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Wired up in markup.")]
        private void DropDownToggle_Click(object sender, RoutedEventArgs e)
        {
            FrameworkElement fe = sender as FrameworkElement;
            AutoCompleteBox acb = null;
            while (fe != null && acb == null)
            {
                fe = VisualTreeHelper.GetParent(fe) as FrameworkElement;
                acb = fe as AutoCompleteBox;
            }
            if (acb != null)
            {
                if (string.IsNullOrEmpty(acb.SearchText))
                {
                    acb.Text = string.Empty;
                }
                acb.IsDropDownOpen = !acb.IsDropDownOpen;
            }
        }
        #endregion Events

        #endregion Private
    }
}